home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / Libraries / Sherlock 2.0 / DevLibSrc / Main_DevLib / LIBcvt.c < prev    next >
Text File  |  1996-02-05  |  13KB  |  560 lines

  1. /*
  2.     devlib: Integer and string conversion library.
  3.     
  4.     Do not use Sherlock macros in this file.
  5.     Older versions of Sherlock routines called routines in this file.
  6.     
  7.     All routines in this file convert an entity to a string in a buffer passed by the caller.
  8.     We could replace the calls to PERM_ASSERT by a routine that would fill the
  9.     buffer with a special pattern, say asterisks, when the buffer is too small.
  10.     I have not done so because I regard passing a too-small buffer as a programming error.
  11.     This point of view is debatable.
  12.  
  13.     source:  LIBcvt.c
  14.     started: November 4, 1993.
  15.     version:
  16.         February 5, 1996.
  17.             Added support for SYMANTEC_C
  18.         November 8, 1995.
  19.             Added cvt_frac for use by epadfrac.
  20.             Added cvt_l2s.
  21.             Moved cvt_date and cvt_time to LIBtime.c.
  22.             Call end_abort instead of abort.
  23.             Use PERM_ASSERT rather than cvt_check.
  24.         September 25, 1995.
  25.             Added support for Code Warrior.
  26. */
  27.  
  28. #include <LIBlib.h>
  29. #include <LIBend.h>
  30.  
  31. #include <stdio.h>        /* For sprintf. */
  32. #include <string.h>        /* For strlen. */
  33. #include <time.h>
  34.  
  35. /*
  36.     #define CVT_USE_SPRINTF to use sprintf for formatting in various routines.
  37.     We might not want to use sprintf so as to avoid pulling in the floating point library.
  38.     
  39.     An objection to _not_ using sprintf is that the cvt_l2s assumes a 2's complement
  40.     representation of signed numbers.  You could consider this a bug.
  41.     
  42.     There are subtle differences between the cvt_l2s, cvt_ul2s and cvt_hex2s routines
  43.     having to do with conversions between signed and unsigned quantities.
  44.     It seems clearest and safest to use three separate routines so that types
  45.     of all arguments are manifest.  This may be an overly cautious approach.
  46. */
  47. #undef CVT_USE_SPRINTF
  48.  
  49. char *
  50. cvt_bool(bool b)
  51. {
  52.     return (b) ? "TRUE" : "FALSE";
  53. }
  54.  
  55. char *
  56. cvt_cat2(char * buffer, int buf_size, char * s1, char * s2)
  57. {
  58.     register size_t length1 = strlen(s1);
  59.     register size_t length2 = strlen(s2);
  60.  
  61.     PERM_ASSERT(length1 + length2 + 1 < buf_size);
  62.     
  63.     strcpy(buffer, s1);
  64.     strcpy(buffer+length1, s2);
  65.     return buffer;
  66. }
  67.  
  68. char *
  69. cvt_cat3(char * buffer, int buf_size, char * s1, char * s2, char *s3)
  70. {
  71.     size_t length1 = strlen(s1);
  72.     size_t length2 = strlen(s2);
  73.     size_t length3 = strlen(s3);
  74.  
  75.     PERM_ASSERT(length1 + length2 + length3 + 1 < buf_size);
  76.  
  77.     strcpy(buffer, s1);
  78.     strcpy(buffer+length1, s2);
  79.     strcpy(buffer+length1+length2, s3);
  80.  
  81.     return buffer;
  82. }
  83.  
  84. char *
  85. cvt_char(char * buffer, int buf_size, int c)
  86. {
  87.     PERM_ASSERT(buf_size > 2);
  88.  
  89.     buffer[0] = c;
  90.     buffer[1] = '\0';
  91.  
  92.     return buffer;
  93. }
  94.  
  95. /*
  96.     Return a descriptive message corresponding to a file error code.
  97. */
  98. #if defined(THINK_C) || defined(SYMANTEC_C) || defined(applec) || defined(__MWERKS__)
  99.     #include <Errors.h>
  100. #endif
  101.  
  102. char *
  103. cvt_file_error(char * buffer, int buf_size, int OSErrCode)
  104. {
  105.  
  106. #if defined(THINK_C) || defined(SYMANTEC_C) || defined(applec) || defined(__MWERKS__)
  107.  
  108.     int n;
  109.  
  110.     switch(OSErrCode) {
  111.  
  112.     case -120:            return "Directory not found";
  113.     case dirFulErr:        return "Directory full";
  114.     case dskFulErr:     return "Disk full";
  115.     case nsvErr:        return "Volume not found";
  116.     case ioErr:            return "I/O error";
  117.     case bdNamErr:        return "Bad file name";
  118.     case fnOpnErr:        return "File not open";
  119.     case eofErr:        return "End of file";
  120.     case posErr:        return "Position error";
  121.     case tmfoErr:        return "Too many open files";
  122.     case fnfErr:        return "File not found";
  123.     case wPrErr:        return "Volume is software locked";
  124.     case fLckdErr:        return "File is locked";
  125.     case fBsyErr:        return "File is busy";
  126.     case dupFNErr:        return "File exists";
  127.     case opWrErr:        return "File is already open for writing";
  128.     case paramErr:        return "Error in parameter list";
  129.     case rfNumErr:        return "Access path not found";
  130.     case gfpErr:        return "Error during GetFPos";
  131.     case volOffLinErr:    return "Volume off line";
  132.     case permErr:        return "File is locked";
  133.     case volOnLinErr:    return "Volume on line";
  134.     case nsDrvErr:        return "No such drive";
  135.     case noMacDskErr:    return "Not a Macintosh disk";
  136.     case extFSErr:        return "External file system";
  137.     case fsRnErr:        return "Rename error";
  138.     case badMDBErr:        return "Bad master director block";
  139.     case wrPermErr:        return "Writing not allowed";
  140.  
  141.     default:
  142.         
  143.         strcpy(buffer, "Unknown error: ");
  144.         n = cvt_l2s(buffer + strlen(buffer), OSErrCode);
  145.         
  146.         PERM_ASSERT(n < buf_size);
  147.         return buffer;
  148. }
  149.  
  150. #else
  151.  
  152.     PERM_ASSERT(buf_size >= 50);
  153.     strcpy(buffer, "file error code: ");
  154.     cvt_l2s(buffer + strlen(buffer), OSErrCode);
  155.  
  156. #endif
  157.  
  158. }
  159.  
  160. /*
  161.     Convert to a percentage of a2.
  162. */
  163. char *
  164. cvt_frac(char * buffer, int buf_size, long a1, long a2)
  165. {
  166.     #ifdef CVT_USE_SPRINTF
  167.         int n = sprintf(buf, "%ld.%ld", a1/a2, ((10 * a1)/a2) % 10);
  168.     #else
  169.         int n = cvt_l2s(buffer, a1/a2);
  170.         strcat(buffer, ".");
  171.         n += 1 + cvt_l2s(buffer + strlen(buffer), ((10 * a1)/a2) % 10);
  172.     #endif
  173.  
  174.     PERM_ASSERT(n < buf_size);
  175.     return buffer;
  176. }
  177.  
  178. char *
  179. cvt_hex(char * buffer, int buf_size, long hex)
  180. {
  181.     #ifdef CVT_USE_SPRINTF
  182.         int n = sprintf(buffer, "%lx", hex);
  183.     #else
  184.         int n = cvt_hex2s(buffer, hex);
  185.     #endif
  186.     
  187.     PERM_ASSERT(n < buf_size);
  188.     return buffer;
  189. }
  190.  
  191. short
  192. cvt_hex2s (char * buf, ulong val)
  193. {
  194.     short length = 0;
  195.  
  196.     /* Generate the hex digits in reverse order. */
  197.     {
  198.         short i;
  199.  
  200.         for (i = 0; i < sizeof(long) * 2; i++) {
  201.             short digit = (val % 16);
  202.             buf[length++] = digit + ((digit < 10) ? '0' : ('a' - 10));
  203.             val /= 16;
  204.         }
  205.     }
  206.     
  207.     /* Reverse the digits. */
  208.     {
  209.         short i = 0;
  210.         short j = length-1;
  211.         
  212.         while (i < j) {
  213.             char temp = buf[j];
  214.             buf[j] = buf[i];
  215.             buf[i] = temp;
  216.             i++; j--;
  217.         }
  218.     }
  219.     
  220.     buf[length] = '\0';
  221.     return length;
  222. }
  223.  
  224. char *
  225. cvt_int    (char * buffer, int buf_size, int i)
  226. {
  227.     #ifdef CVT_USE_SPRINTF
  228.         int n = sprintf(buffer, "%d", i);
  229.     #else
  230.         int n = cvt_l2s(buffer, i);
  231.     #endif
  232.  
  233.     PERM_ASSERT(n < buf_size);
  234.     return buffer;
  235. }
  236.  
  237. char *
  238. cvt_long (char * buffer, int buf_size, long a)
  239. {
  240.     #ifdef CVT_USE_SPRINTF
  241.         int n = sprintf(buffer, "%ld", a);
  242.     #else
  243.         int n = cvt_l2s(buffer, a);
  244.     #endif
  245.  
  246.     PERM_ASSERT(n < buf_size);
  247.     return buffer;
  248. }
  249.  
  250. short
  251. cvt_l2s (char * buf, long val)
  252. {
  253.     short length = 0;
  254.     
  255.     /*
  256.         Check for the one case that can cause overflow.
  257.         In two's complement machines the largest negative number has no positive counterpart.
  258.         
  259.         WARNING: this code assumes we have a 2's complement representation of signed numbers.
  260.     */
  261.     if (val == 0x80000000) {
  262.         strcpy(buf, "-2147483648");
  263.         return strlen(buf);
  264.     }
  265.     
  266.     if (val < 0) {
  267.         buf[length++] = '-';
  268.         val = -val;                /* This can no longer overflow. */
  269.         PERM_ASSERT(val >= 0);
  270.     }
  271.     
  272.     /* Generate the digits in reverse order. */
  273.     do {
  274.         buf[length++] = (val % 10) + '0';
  275.         val /= 10;
  276.     }
  277.     while (val > 0);
  278.     
  279.     /* Reverse the digits. */
  280.     {
  281.         short i = (buf[0] == '-');
  282.         short j = length-1;
  283.         
  284.         while (i < j) {
  285.             char temp = buf[j];
  286.             buf[j] = buf[i];
  287.             buf[i] = temp;
  288.             i++; j--;
  289.         }
  290.     }
  291.     
  292.     buf[length] = '\0';
  293.     return length;
  294. }
  295.  
  296. char *
  297. cvt_paren(char * buffer, int buf_size, char *s)
  298. {
  299.     PERM_ASSERT(2 + strlen(s) <  buf_size);
  300.  
  301.     strcpy(buffer, "(");
  302.     strcat(buffer, s);
  303.     strcat(buffer, ")");
  304.  
  305.     return buffer;
  306. }
  307.  
  308. /*
  309.     Convert to an "integer" percentage, like baseball batting averages.
  310. */
  311. int
  312. cvt_1000percent(long n, ulong tot)
  313. {
  314.     double dn     = n;
  315.     double dt     = tot;
  316.     double d1000 = 1000;
  317.     double val     = dn / dt;
  318.  
  319.     if (n == 0 || tot == 0) {
  320.         return 0;
  321.     }
  322.  
  323.     return (int) (d1000 * val);
  324. }
  325.  
  326. /*
  327.     Convert to a percentage of n of total.
  328. */
  329. char *
  330. cvt_percent(char * buffer, int buf_size, long longv, ulong tot)
  331. {
  332.     int n;
  333.     int percent;
  334.  
  335.     percent = cvt_1000percent(longv, tot);
  336.  
  337.     #ifdef CVT_USE_SPRINTF
  338.         n = sprintf(buffer, "%d.%d", (percent/10), (percent%10));
  339.     #else
  340.         n = cvt_l2s(buffer, percent/10);
  341.         strcat(buffer, ".");
  342.         n += 1 + cvt_l2s(buffer + strlen(buffer), percent % 10);
  343.     #endif
  344.  
  345.     PERM_ASSERT(n < buf_size);
  346.     return buffer;
  347. }
  348.  
  349. /*
  350.     Convert a pascal pointer to a C pointer.
  351. */
  352. char *
  353. cvt_pstring(char * buffer, int buf_size, pstring p)
  354. {
  355.     register int    i;
  356.     register int    length = *p++;
  357.  
  358.     PERM_ASSERT(length+1 < buf_size);
  359.  
  360.     for (i = 0; i < length; i++) {
  361.         buffer[i] = *p++;
  362.     }
  363.     buffer[i] = '\0';
  364.     return buffer;
  365. }
  366.  
  367. char *
  368. cvt_ptr (char * buffer, int buf_size, void * p)
  369. {
  370.     #ifdef CVT_USE_SPRINTF
  371.         int n = sprintf(buffer, "%p", p);
  372.     #else
  373.         int n = cvt_hex2s(buffer, (ulong) p);
  374.     #endif
  375.  
  376.     PERM_ASSERT(n < buf_size);
  377.     return buffer;
  378. }
  379.  
  380. /*
  381.     Return a string in quotes.
  382.     No quoting of quotes is done within the string.
  383. */
  384. char *
  385. cvt_quote(char * buffer, int buf_len, char * s)
  386. {
  387.     PERM_ASSERT(strlen(s) + 3 <  buf_len);
  388.  
  389.     strcpy(buffer, "\"");
  390.     strcat(buffer, s);
  391.     strcat(buffer, "\"");
  392.  
  393.     return buffer;
  394. }
  395.  
  396. /*
  397.     Given a static string, return the short file name of the string.
  398. */
  399. char *
  400. cvt_short_fn(char * file_name)
  401. {
  402.  
  403.     #if defined(THINK_C) || defined(SYMANTEC_C) || defined(applec) || defined(TUPLE_C) || defined(__MWERKS__)
  404.     
  405.         /* Scan backwards looking for a colon. */
  406.         register size_t n = strlen(file_name)-2;
  407.         /*
  408.             Bug fix: 11/8/93:
  409.             size_t may be unsigned, in which case i < 0 is *never* true.
  410.         */
  411.         register long i;
  412.         for (i = n; i >= 0; i--) {
  413.             if (file_name[i] == ':') {
  414.                 return file_name + i + 1;
  415.             }
  416.         }
  417.         return file_name;
  418.     #else
  419.         return file_name;
  420.     #endif
  421.  
  422. }
  423.  
  424. /*
  425.     Test this module for blunders.
  426. */
  427. #define BUF_SIZE 50
  428.  
  429. #ifndef PRODUCTION
  430.  
  431. void
  432. cvt_test(void)
  433. {
  434.     char buf [BUF_SIZE];
  435.  
  436.     ecnl();
  437.     es("cvt_test...\n\n");
  438.     es("error code 1234: "); es(cvt_file_error(buf, BUF_SIZE, 1234)); enl();
  439.     es("TRUE:            "); es(cvt_bool(TRUE)); enl();
  440.     es("FALSE:           "); es(cvt_bool(FALSE)); enl();
  441.     es("char A:          "); es(cvt_char(buf, BUF_SIZE, 'A')); enl();
  442.     
  443.     #if 0 // Don't force the floating library to be linked in
  444.  
  445.         es("The following requires the floating library to be linked in...\n");
  446.         es("Do NOT use ANSI-small: sprintf(\"%f\"...) will return 0!\n");
  447.         es("double 1.1:      "); es(cvt_double(buf, BUF_SIZE, (double) 1.1)); enl();
  448.     
  449.     #endif
  450.  
  451.     es("int -25:         "); es(cvt_int        (buf, BUF_SIZE, -25)); enl();
  452.     es("long 987654321:  "); es(cvt_long    (buf, BUF_SIZE, 987654321)); enl();
  453.     es("hex abcdef00:    "); es(cvt_hex        (buf, BUF_SIZE, 0xabcdef00)); enl();
  454.     es("hex 01236789:    "); es(cvt_hex        (buf, BUF_SIZE, 0x01236789)); enl();
  455.     es("ptr 1158a2f      "); es(cvt_ptr        (buf, BUF_SIZE, (void *) 0x1158a2f)); enl();
  456.     es("uint 32000       "); es(cvt_uint    (buf, BUF_SIZE, (unsigned) 32000)); enl();
  457.     es("uint 0x8000      "); es(cvt_uint    (buf, BUF_SIZE, (unsigned) 0x8000)); enl();
  458.     es("ulong 87654321   "); es(cvt_ulong    (buf, BUF_SIZE, (unsigned long) 87654321)); enl();
  459.     es("ulong 0x80000000 "); es(cvt_ulong    (buf, BUF_SIZE, (unsigned long) 0x80000000)); enl();
  460.     es("long  0x80000000 "); es(cvt_long    (buf, BUF_SIZE, (long) 0x80000000)); enl();
  461.     es("ulong 2147483648 "); es(cvt_ulong    (buf, BUF_SIZE, (ulong) 2147483648)); enl();
  462.     es("long  2147483648 "); es(cvt_long    (buf, BUF_SIZE, (long)  2147483648)); enl();
  463.     es("quote A:         "); es(cvt_quote    (buf, BUF_SIZE, "A")); enl();
  464.     es("pstring \\pABCD   ");es(cvt_pstring    (buf, BUF_SIZE, "\pABCD")); enl();
  465.     es("trunc(ABC,2)     "); es(cvt_trunc    (buf, BUF_SIZE, "ABC", 2)); enl();
  466.     es("percent(45,200)  "); es(cvt_percent    (buf, BUF_SIZE, 45, 200)); enl();
  467.     
  468.     ecnls(2);
  469.     es("test of exxx routines that may call cvt routines...\n\n");
  470.     
  471.     es("int -25:         "); epadint    (-25, 0); enl();
  472.     es("long 987654321:  "); epadlong    (987654321, 0); enl();
  473.     es("hex abcdef00:    "); epadhex    (0xabcdef00, 0); enl();
  474.     es("hex 01236789:    "); epadhex    (0x01236789, 0); enl();
  475.     es("ptr 1158a2f      "); epadptr    ((void *) 0x1158a2f, 0); enl();
  476.     es("uint 32000       "); epaduint    ((unsigned) 32000, 0); enl();
  477.     es("uint 0x8000      "); epaduint    ((unsigned) 0x8000, 0); enl();
  478.     es("ulong 87654321   "); epadulong    ((unsigned long) 87654321, 0); enl();
  479.     es("ulong 0x80000000 "); epadulong    ((unsigned long) 0x80000000, 0); enl();
  480.     es("long  0x80000000 "); epadlong    ((long) 0x80000000, 0); enl();
  481.     es("ulong 2147483648 "); epadulong    ((ulong) 2147483648, 0); enl();
  482.     es("long  2147483648 "); epadlong    ((long)  2147483648, 0); enl();
  483.     es("frac(45,200)     "); epadfrac    (45, 200, 0); enl();
  484. }
  485.  
  486. #endif /* PRODUCTION */
  487.  
  488. /*
  489.     Return a string truncated to n digits.
  490. */
  491. char *
  492. cvt_trunc (char * buffer, int buf_size, char *s, int n)
  493. {
  494.     register int i;
  495.     register size_t length = strlen(s);
  496.  
  497.     PERM_ASSERT(n < buf_size);
  498.  
  499.     for (i = 0; i < n; i++) {
  500.         buffer[i] = *s++;
  501.     }
  502.     buffer[i] = '\0';
  503.     return buffer;
  504. }
  505.  
  506. char *
  507. cvt_uint (char * buffer, int buf_size, uint ui)
  508. {
  509.     #ifdef CVT_USE_SPRINTF
  510.         int n = sprintf(buffer, "%u", ui);
  511.     #else
  512.         int n = cvt_ul2s(buffer, ui);
  513.     #endif
  514.     
  515.     PERM_ASSERT(n < buf_size);
  516.     return buffer;
  517. }
  518.  
  519. char *
  520. cvt_ulong (char * buffer, int buf_size, ulong ul)
  521. {
  522.     #ifdef CVT_USE_SPRINTF
  523.         int n = sprintf(buffer, "%lu", ul);
  524.     #else
  525.         int n = cvt_ul2s(buffer, ul);
  526.     #endif
  527.  
  528.     PERM_ASSERT(n < buf_size);
  529.     return buffer;
  530. }
  531.  
  532. short
  533. cvt_ul2s (char * buf, ulong val)
  534. {
  535.     short length = 0;
  536.     
  537.     /* Generate the digits in reverse order. */
  538.     do {
  539.         buf[length++] = (val % 10) + '0';
  540.         val /= 10;
  541.     }
  542.     while (val > 0);
  543.     
  544.     /* Reverse the digits. */
  545.     {
  546.         short i = 0;
  547.         short j = length-1;
  548.         
  549.         while (i < j) {
  550.             char temp = buf[j];
  551.             buf[j] = buf[i];
  552.             buf[i] = temp;
  553.             i++; j--;
  554.         }
  555.     }
  556.     
  557.     buf[length] = '\0';
  558.     return length;
  559. }
  560.